﻿using System;
using System . Collections . Generic;
using System . Linq;
using System . Text;
using System . Collections;
using System . Xml . Linq;

using System . Threading . Tasks;

namespace GameClassLibrary
{
    public abstract class GameObject
    {
        public static List<GameObject> GameObjectList { get; private set; } = new List<GameObject> ( );

        public long Index { get; set; }

        public abstract void NextDay ( );

        public static GameObject GetObject ( long index )
        {
            var temp = from tpm in GameObjectList
                       where tpm . Index == index
                       select tpm;
            return temp . FirstOrDefault ( );
        }

        public GameObject ( XElement saving ) : this ( )
        {
            Index = ( long ) saving . Attribute ( "Index" );
            foreach ( var property in GetType ( ) . GetProperties ( ) )
            {
                if ( Attribute . GetCustomAttribute ( property , typeof ( SaveValueAttribute ) ) != null )
                {
                    if ( property . PropertyType . IsSubclassOf ( typeof ( GameObject ) ) )
                    {
                        temp . Add ( ( property . GetValue ( this , null ) as GameObject ) . Save ( ) );
                    }
                    property . SetValue ( this , Convert . ChangeType ( saving . Attribute ( property . Name ) . Value , property . PropertyType , null ) , null );
                }
                else33
                {
                    if ( Attribute . GetCustomAttribute ( property , typeof ( SaveReferenceAttribute ) ) != null )
                    {
                        Game . RegisterForLoad ( this , property . PropertyType , property . Name , Convert . ToInt64 ( saving . Attribute ( property . Name ) . Value ) );
                    }
                    else
                    {
                        if ( Attribute . GetCustomAttribute ( property , typeof ( SaveValueListAttribute ) ) != null )
                        {
                            foreach ( var sav in saving . Element ( property . Name ) . Descendants ( property . PropertyType . ToString ( ) ) )
                            {
                                ( property . GetValue ( this , null ) as List<GameObject> ) . Add ( ( GameObject ) property . PropertyType . GetConstructor ( new Type [ ] { typeof ( XElement ) } ) . Invoke ( new object [ ] { sav } ) );
                            }
                        }
                        else
                        {
                            if ( Attribute . GetCustomAttribute ( property , typeof ( SaveReferenceListAttribute ) ) != null )
                            {
                                foreach ( var sav in saving . Element ( property . Name ) . Descendants ( property . PropertyType . ToString ( ) ) )
                                {
                                    Game . RegisterForLoad ( this , property . PropertyType , property . Name , ( long ) saving . Attribute ( property . Name ) );
                                }
                            }
                        }
                    }
                }
            }
        }

        public GameObject ( )
        {
            Index = this . GetHashCode ( );
            GameObject . GameObjectList . Add ( this );
        }


        public virtual XElement Save ( )
        {
            var temp = new XElement ( GetType ( ) . ToString ( ) );

            temp . SetAttributeValue ( "Index" , Index );

            foreach ( var property in GetType ( ) . GetProperties ( ) )
            {
                if ( property . GetValue ( this , null ) != null )
                {
                    if ( Attribute . GetCustomAttribute ( property , typeof ( SaveValueAttribute ) ) != null )
                    {
                        if ( property . PropertyType . IsSubclassOf ( typeof ( GameObject ) ) )
                        {
                            temp . Add ( ( property . GetValue ( this , null ) as GameObject ) . Save ( ) );
                        }
                        else
                        {
                            temp . SetAttributeValue ( property . Name , property . GetValue ( this , null ) );
                        }
                    }
                    else
                    {
                        if ( Attribute . GetCustomAttribute ( property , typeof ( SaveReferenceAttribute ) ) != null )
                        {
                            temp . SetAttributeValue ( property . Name , ( property . GetValue ( this , null ) as GameObject ) . Index );
                        }
                        else
                        {
                            if ( Attribute . GetCustomAttribute ( property , typeof ( SaveValueListAttribute ) ) != null )
                            {

                                XElement element = new XElement ( property . Name );

                                foreach ( var item in ( property . GetValue ( this , null ) as IEnumerable ) )
                                {
                                    if ( item . GetType ( ) . IsSubclassOf ( typeof ( GameObject ) ) )
                                    {
                                        element . Add ( ( item as GameObject ) . Save ( ) );
                                    }
                                    else
                                    {
                                        XElement ele = new XElement ( item . GetType ( ) . ToString ( ) );
                                        ele . Value = item . ToString ( );
                                        element . Add ( ele );
                                    }
                                }
                                temp . Add ( element );
                            }
                            else
                            {
                                if ( Attribute . GetCustomAttribute ( property , typeof ( SaveReferenceListAttribute ) ) != null )
                                {
                                    XElement element = new XElement ( property . Name );
                                    foreach ( var item in ( property . GetValue ( this , null ) as IEnumerable ) )
                                    {
                                        element . Add ( ( item as GameObject ) . Index );
                                    }
                                    temp . Add ( element );
                                }
                            }
                        }
                    }
                }
            }
            return temp;

        }
    }
}
